using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using AutoMapper;
using AiPlatformAdmin.Api.Data;
using AiPlatformAdmin.Api.Models;
using AiPlatformAdmin.Api.Services;
using AiPlatformAdmin.Api.DTOs.Teams;

namespace AiPlatformAdmin.Api.Controllers;

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class TeamsController : ControllerBase
{
    private readonly AppDbContext _context;
    private readonly ITenantService _tenantService;
    private readonly IMapper _mapper;

    public TeamsController(AppDbContext context, ITenantService tenantService, IMapper mapper)
    {
        _context = context;
        _tenantService = tenantService;
        _mapper = mapper;
    }

    private int GetCurrentUserId()
    {
        var userIdClaim = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        return int.TryParse(userIdClaim, out int userId) ? userId : 0;
    }

    private async Task<bool> IsUserTeamAdmin(int teamId, int userId)
    {
        if (User.IsInRole("Administrator")) return true;
        return await _context.TeamAdmins.AnyAsync(ta => ta.TeamId == teamId && ta.UserId == userId);
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<TeamDto>>> GetTeams()
    {
        var teams = await _context.Teams
            .Include(t => t.UserTeams)
            .Include(t => t.TeamAdmins)
            .ToListAsync();

        return Ok(_mapper.Map<IEnumerable<TeamDto>>(teams));
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<TeamDto>> GetTeam(int id)
    {
        var team = await _context.Teams
            .Include(t => t.UserTeams)
            .Include(t => t.TeamAdmins)
            .FirstOrDefaultAsync(t => t.Id == id);

        if (team == null)
        {
            return NotFound();
        }

        return Ok(_mapper.Map<TeamDto>(team));
    }

    [HttpPost]
    [Authorize(Roles = "PlatformUser,Administrator")]
    public async Task<ActionResult<TeamDto>> CreateTeam(CreateTeamDto dto)
    {
        if (!_tenantService.CurrentTenantId.HasValue)
        {
            return Forbid();
        }

        var userId = GetCurrentUserId();
        var team = _mapper.Map<Team>(dto);

        _context.Teams.Add(team);
        await _context.SaveChangesAsync();

        // Make the creator a team admin
        if (!User.IsInRole("Administrator"))
        {
            _context.TeamAdmins.Add(new TeamAdmin
            {
                TeamId = team.Id,
                UserId = userId
            });
        }

        // Add admin users
        if (dto.AdminUserIds != null && dto.AdminUserIds.Any())
        {
            foreach (var adminUserId in dto.AdminUserIds)
            {
                if (!await _context.TeamAdmins.AnyAsync(ta => ta.TeamId == team.Id && ta.UserId == adminUserId))
                {
                    _context.TeamAdmins.Add(new TeamAdmin { TeamId = team.Id, UserId = adminUserId });
                }
            }
        }

        // Add member users
        if (dto.MemberUserIds != null && dto.MemberUserIds.Any())
        {
            foreach (var memberUserId in dto.MemberUserIds)
            {
                _context.UserTeams.Add(new UserTeam { TeamId = team.Id, UserId = memberUserId });
            }
        }

        await _context.SaveChangesAsync();

        // Reload with all relationships
        await _context.Entry(team).Collection(t => t.UserTeams).LoadAsync();
        await _context.Entry(team).Collection(t => t.TeamAdmins).LoadAsync();

        return CreatedAtAction(nameof(GetTeam), new { id = team.Id }, _mapper.Map<TeamDto>(team));
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> UpdateTeam(int id, UpdateTeamDto dto)
    {
        var userId = GetCurrentUserId();
        if (!await IsUserTeamAdmin(id, userId))
        {
            return Forbid();
        }

        var team = await _context.Teams
            .Include(t => t.UserTeams)
            .Include(t => t.TeamAdmins)
            .FirstOrDefaultAsync(t => t.Id == id);

        if (team == null)
        {
            return NotFound();
        }

        _mapper.Map(dto, team);

        // Update admins if provided
        if (dto.AdminUserIds != null)
        {
            var existingAdmins = team.TeamAdmins.Select(ta => ta.UserId).ToList();
            var newAdmins = dto.AdminUserIds.ToList();

            var toAdd = newAdmins.Except(existingAdmins);
            var toRemove = existingAdmins.Except(newAdmins);

            foreach (var adminUserId in toAdd)
            {
                _context.TeamAdmins.Add(new TeamAdmin { TeamId = id, UserId = adminUserId });
            }

            foreach (var adminUserId in toRemove)
            {
                var adminToRemove = team.TeamAdmins.FirstOrDefault(ta => ta.UserId == adminUserId);
                if (adminToRemove != null)
                {
                    _context.TeamAdmins.Remove(adminToRemove);
                }
            }
        }

        // Update members if provided
        if (dto.MemberUserIds != null)
        {
            var existingMembers = team.UserTeams.Select(ut => ut.UserId).ToList();
            var newMembers = dto.MemberUserIds.ToList();

            var toAdd = newMembers.Except(existingMembers);
            var toRemove = existingMembers.Except(newMembers);

            foreach (var memberUserId in toAdd)
            {
                _context.UserTeams.Add(new UserTeam { TeamId = id, UserId = memberUserId });
            }

            foreach (var memberUserId in toRemove)
            {
                var memberToRemove = team.UserTeams.FirstOrDefault(ut => ut.UserId == memberUserId);
                if (memberToRemove != null)
                {
                    _context.UserTeams.Remove(memberToRemove);
                }
            }
        }

        await _context.SaveChangesAsync();
        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteTeam(int id)
    {
        var userId = GetCurrentUserId();
        if (!await IsUserTeamAdmin(id, userId))
        {
            return Forbid();
        }

        var team = await _context.Teams.FindAsync(id);
        if (team == null)
        {
            return NotFound();
        }

        _context.Teams.Remove(team);
        await _context.SaveChangesAsync();

        return NoContent();
    }
}
